<template>
  <div class="course-browse">
    <header class="course-browse__hero">
      <div class="course-browse__hero-text">
        <h1>课程浏览中心</h1>
        <p>
          搜索与筛选心理课程，按能力目标、难度与标签组合快速定位最适合你的成长路径。
        </p>
      </div>
      <div class="course-browse__controls">
        <el-input
          v-model="searchTerm"
          placeholder="搜索课程、讲师或关键词"
          size="large"
          clearable
          @clear="handleFiltersChange"
          @input="handleFiltersChange"
        />
        <el-select
          v-model="selectedDifficulty"
          placeholder="学习阶段"
          size="large"
          class="course-browse__difficulty"
          @change="handleFiltersChange"
        >
          <el-option label="全部难度" value="ALL" />
          <el-option label="入门" value="BEGINNER" />
          <el-option label="进阶" value="INTERMEDIATE" />
          <el-option label="高阶" value="ADVANCED" />
        </el-select>
      </div>
    </header>

    <section class="course-browse__filters" aria-label="课程分类筛选">
      <button
        type="button"
        class="filter-chip"
        :class="{ 'filter-chip--active': !selectedCategory }"
        @click="toggleCategory(null)"
      >
        全部分类
      </button>
      <button
        v-for="category in categories"
        :key="category.id"
        type="button"
        class="filter-chip"
        :class="{ 'filter-chip--active': selectedCategory === category.id }"
        @click="toggleCategory(category.id)"
      >
        {{ category.name }}
      </button>
    </section>

    <section class="course-browse__results">
      <header class="course-browse__results-header">
        <h2>共 {{ filteredCourses.length }} 门课程</h2>
        <span v-if="selectedCategory" class="course-browse__results-filter">分类：{{ activeCategoryName }}</span>
      </header>
      <div v-if="filteredCourses.length" class="course-browse__grid">
        <article
          v-for="course in filteredCourses"
          :key="course.id"
          class="browse-card"
          :class="{ 'browse-card--highlight': course.id === highlightedCourseId }"
          role="button"
          tabindex="0"
          @click="handleCourseSelect(course)"
          @keyup.enter="handleCourseSelect(course)"
          @keyup.space.prevent="handleCourseSelect(course)"
        >
          <div class="browse-card__media">
            <img :src="course.coverImage" :alt="course.title" loading="lazy" />
            <span class="browse-card__badge" v-if="course.highlightTag">{{ course.highlightTag }}</span>
          </div>
          <div class="browse-card__body">
            <div class="browse-card__meta">
              <span>{{ difficultyLabels[course.difficulty || 'BEGINNER'] }}</span>
              <span>{{ course.instructorName }}</span>
            </div>
            <h3>{{ course.title }}</h3>
            <p>{{ course.description }}</p>
            <div class="browse-card__footer">
              <div class="browse-card__tags">
                <span v-for="tag in course.tags" :key="tag" class="browse-card__tag">{{ tag }}</span>
              </div>
              <span class="browse-card__price">{{ course.priceLabel }}</span>
            </div>
          </div>
        </article>
      </div>
      <el-empty
        v-else
        description="未找到符合条件的课程，可尝试调整筛选条件"
        image-size="160"
      />
    </section>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'

import {
  courseCategoriesMock,
  courseCatalogMock,
  playlistItemsMock,
  instructorHighlightsMock,
  featuredCoursesMock,
  liveEventsMock,
} from './course.mock'
import type { CourseCategory, CourseItem } from '../../types/course/Course.ts'

defineOptions({
  name: 'CourseBrowseView',
})

const router = useRouter()
const route = useRoute()

const categories = ref<CourseCategory[]>(courseCategoriesMock)
const allCourses = ref<CourseItem[]>(courseCatalogMock)

const searchTerm = ref('')
const selectedCategory = ref<string | null>(null)
const selectedDifficulty = ref<'ALL' | NonNullable<CourseItem['difficulty']>>('ALL')
const highlightedCourseId = ref<string | null>(null)

const difficultyLabels: Record<'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED', string> = {
  BEGINNER: '入门',
  INTERMEDIATE: '进阶',
  ADVANCED: '高阶',
}

const activeCategoryName = computed(() => {
  if (!selectedCategory.value) {
    return '全部'
  }
  return categories.value.find((c) => c.id === selectedCategory.value)?.name ?? '全部'
})

const filteredCourses = computed(() => {
  const term = searchTerm.value.trim().toLowerCase()
  return allCourses.value.filter((course) => {
    const matchesSearch = term
      ? [course.title, course.description, course.instructorName, ...(course.tags ?? [])]
          .join(' ')
          .toLowerCase()
          .includes(term)
      : true

    const matchesCategory = selectedCategory.value
      ? course.categoryIds?.includes(selectedCategory.value) ?? false
      : true

    const matchesDifficulty =
      selectedDifficulty.value === 'ALL' || course.difficulty === selectedDifficulty.value

    return matchesSearch && matchesCategory && matchesDifficulty
  })
})

const buildQueryFromState = (): Record<string, string> => {
  const query: Record<string, string> = {}

  if (selectedCategory.value) {
    query.category = selectedCategory.value
  }

  if (selectedDifficulty.value !== 'ALL') {
    query.difficulty = selectedDifficulty.value
  }

  if (searchTerm.value.trim()) {
    query.q = searchTerm.value.trim()
  }

  if (highlightedCourseId.value) {
    query.course = highlightedCourseId.value
  }

  return query
}

const serializeQuery = (query: Record<string, unknown>): string => {
  return Object.keys(query)
    .sort()
    .map((key) => {
      const value = query[key]
      if (Array.isArray(value)) {
        return `${key}:${value.join(',')}`
      }
      return `${key}:${value ?? ''}`
    })
    .join('|')
}

const syncQueryToState = () => {
  const nextQuery = buildQueryFromState()
  const currentSerialized = serializeQuery(route.query as Record<string, unknown>)
  const nextSerialized = serializeQuery(nextQuery)

  if (currentSerialized === nextSerialized) {
    return
  }

  router.replace({ name: 'course-browse', query: nextQuery })
}

const applyRouteToState = () => {
  const { category, difficulty, q, course, playlist, instructor, event } = route.query

  selectedCategory.value = typeof category === 'string' ? category : null
  selectedDifficulty.value =
    typeof difficulty === 'string' && ['BEGINNER', 'INTERMEDIATE', 'ADVANCED'].includes(difficulty)
      ? (difficulty as typeof selectedDifficulty.value)
      : 'ALL'
  searchTerm.value = typeof q === 'string' ? q : ''
  highlightedCourseId.value = typeof course === 'string' ? course : null

  if (!searchTerm.value) {
    if (typeof playlist === 'string') {
      const playlistMatch = playlistItemsMock.find((item) => item.id === playlist)
      if (playlistMatch) {
        searchTerm.value = playlistMatch.title
      }
    } else if (typeof instructor === 'string') {
      const instructorMatch = instructorHighlightsMock.find((item) => item.id === instructor)
      if (instructorMatch) {
        searchTerm.value = instructorMatch.name
      }
    } else if (typeof event === 'string') {
      const eventMatch = liveEventsMock.find((item) => item.id === event)
      if (eventMatch) {
        searchTerm.value = eventMatch.title
      }
    } else if (highlightedCourseId.value) {
      const courseMatch = featuredCoursesMock.find((item) => item.id === highlightedCourseId.value)
      if (courseMatch) {
        searchTerm.value = courseMatch.title
      }
    }
  }

  syncQueryToState()
}

const handleFiltersChange = () => {
  syncQueryToState()
}

const toggleCategory = (id: string | null) => {
  selectedCategory.value = id
  handleFiltersChange()
}

const openCourseDetail = (courseId: string) => {
  const resolved = router.resolve({ name: 'course-detail', params: { courseId } })
  if (typeof window !== 'undefined') {
    window.open(resolved.href, '_blank', 'noopener')
  }
}

const handleCourseSelect = (course: CourseItem) => {
  highlightedCourseId.value = course.id
  if (course.categoryIds?.length) {
    selectedCategory.value = course.categoryIds[0]
  }
  handleFiltersChange()
  openCourseDetail(course.id)
}

watch(
  () => route.query,
  () => {
    applyRouteToState()
  },
  { immediate: true },
)
</script>

<style scoped>
.course-browse {
  display: flex;
  flex-direction: column;
  gap: 32px;
  padding: 48px 64px 80px;
  background-color: #f8f9fb;
  min-height: 100vh;
}

.course-browse__hero {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.course-browse__hero-text h1 {
  font-size: 36px;
  font-weight: 700;
  color: #1f2937;
}

.course-browse__hero-text p {
  font-size: 18px;
  color: #4b5563;
  line-height: 1.6;
  max-width: 720px;
}

.course-browse__controls {
  display: flex;
  gap: 16px;
  align-items: center;
}

.course-browse__difficulty {
  min-width: 180px;
}

.course-browse__filters {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.filter-chip {
  padding: 10px 20px;
  border-radius: 999px;
  border: 1px solid rgba(60, 101, 245, 0.35);
  background: rgba(60, 101, 245, 0.08);
  color: #3c65f5;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.filter-chip--active {
  background: #3c65f5;
  color: #fff;
  box-shadow: 0 8px 16px rgba(60, 101, 245, 0.24);
}

.course-browse__results {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.course-browse__results-header {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
}

.course-browse__results-header h2 {
  font-size: 24px;
  font-weight: 700;
}

.course-browse__results-filter {
  color: #6b7280;
}

.course-browse__grid {
  display: grid;
  gap: 28px;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

.browse-card {
  display: flex;
  flex-direction: column;
  border-radius: 24px;
  background: #fff;
  box-shadow: 0 20px 40px rgba(15, 23, 42, 0.08);
  overflow: hidden;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  outline: none;
}

.browse-card:hover,
.browse-card:focus-visible {
  transform: translateY(-6px);
  box-shadow: 0 28px 48px rgba(15, 23, 42, 0.12);
}

.browse-card--highlight {
  border: 2px solid #3c65f5;
}

.browse-card__media {
  position: relative;
}

.browse-card__media img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.browse-card__badge {
  position: absolute;
  top: 16px;
  left: 16px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  color: #ef4444;
  font-weight: 600;
}

.browse-card__body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 24px 28px 28px;
}

.browse-card__meta {
  display: flex;
  justify-content: space-between;
  font-weight: 600;
  color: #4b5563;
}

.browse-card__meta span:first-child {
  color: #3c65f5;
}

.browse-card__body h3 {
  font-size: 20px;
  font-weight: 700;
  color: #111827;
  line-height: 1.4;
}

.browse-card__body p {
  color: #6b7280;
  line-height: 1.6;
}

.browse-card__footer {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}

.browse-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.browse-card__tag {
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.12);
  color: #2563eb;
  font-size: 12px;
  font-weight: 600;
}

.browse-card__price {
  font-weight: 700;
  color: #10b981;
}

@media (max-width: 960px) {
  .course-browse {
    padding: 36px 24px 64px;
  }

  .course-browse__controls {
    flex-direction: column;
    align-items: stretch;
  }

  .course-browse__difficulty {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .course-browse {
    padding: 28px 16px 48px;
    gap: 24px;
  }

  .course-browse__hero-text h1 {
    font-size: 30px;
  }

  .course-browse__hero-text p {
    font-size: 16px;
  }
}
</style>
